home *** CD-ROM | disk | FTP | other *** search
- /*
- * match.c - routines for synchronizing client and server folders,
- * based on the configuration file
- */
-
- #include "RevRdist.h"
- #include "dispatch.h"
- #include <nAppleTalk.h>
- #include <TransSkelProto.h>
- #include <TransDisplayProto.h>
-
- /*
- * define some bit pattern mnemonics indicating where a file/folder
- * name appears
- */
-
- #define xxD 1 /* entry is in control file tree */
- #define xSx 2 /* entry is in server catalog */
- #define Cxx 4 /* entry is in client catalog */
- #define xSD (xSx|xxD) /* and various combinations */
- #define CxD (Cxx|xxD)
- #define CSx (Cxx|xSx)
- #define CSD (Cxx|xSx|xxD)
-
- /*
- * prototypes for local routines
- */
- static tnode_t * checkTypes (dnode_t *, cnode_t *);
- static short least (StringPtr, StringPtr, StringPtr);
- static void mergeActions (actions_t *, actions_t *, actions_t *);
- static void updateFInfo (cnode_t *, cnode_t *, short,
- action_t, action_t, action_t);
-
-
- /*
- *=========================================================================
- * matchFolder - synchronize one folder given in the control file tree
- * entry: first arg = ptr to dnode_t of folder to work on
- * second arg = ptr to default actions to apply
- * third arg = ptr to server dirID of folder equivalent to first arg
- * fourth arg = ptr to client dirID of ditto
- * fifth arg = ptr to boolean true if within junk folder
- *=========================================================================
- */
- DISPATCHED (matchFolder)
- {
- struct lm /* local memory */
- {
- frame_t f; /* basic dispatch frame */
- cnode_t * clientp; /* current client entry */
- cnode_t * serverp; /* current server entry */
- dnode_t * distp; /* current control file entry */
- dnode_t * dt; /* copy of first arg */
- cnode_t * ct; /* client catalog tree */
- cnode_t * st; /* server catalog tree */
- Longint cd; /* copy of fourth arg */
- Longint sd; /* copy of third arg */
- action_t todo; /* choice for multi-state actions */
- cnode_t tcn; /* dummy client catalog entry */
- dnode_t tdn; /* dummy control file entry */
- cnode_t tsn; /* dummy server catalog entry */
- StringPtr name; /* folder name */
- actions_t da; /* default actions for folder */
- Boolean ij; /* true if within junk folder */
- };
- typedef struct lm lm_t;
- register lm_t * m;
-
- struct actions ca; /* current actions */
- register cnode_t * clientp; /* copy of lm.clientp */
- StringPtr cname; /* client entry name */
- ctype_t ctype; /* entry for file or folder */
- dnode_t * distp; /* copy of lm.distp */
- StringPtr dname; /* control file entry name */
- OSErr error;
- action_t forcedIC; /* forced "ifClient" action */
- int len; /* string length temp */
- StringPtr name; /* name of current entry */
- Ptr paramv[5]; /* param for called dispatch routines */
- short result; /* our return value */
- cnode_t * serverp; /* copy of lm.serverp */
- StringPtr sname; /* server entry name */
- Longint temp; /* temp dir ID */
- action_t todo; /* action to perform */
- tnode_t * tp; /* ptr to type_node matching file */
- short whereisit; /* bits set per location of file/folder */
- short wherereal; /* original copy of whereisit */
-
- error = 0;
- result = request;
- m = *(lm_t **)fh;
- switch (request)
- {
- case R_INIT:
- if (error = resizeFrame (fh, sizeof (lm_t)))
- return R_ERROR;
- m = *(lm_t **)fh;
- m->dt = (dnode_t *)argv[0];
- m->da = *((actions_t *)argv[1]);
- m->sd = *(Longint *)argv[2];
- m->cd = *(Longint *)argv[3];
- m->ij = *(Boolean *)argv[4];
- m->name = m->dt ? m->dt->name : (SP) "\p<unknown>";
- m->f.state = 1;
- return R_CONT;
-
- case R_BACKOUT:
- case R_QUIT:
- goto cleanexit;
-
- case R_CONT:
- /*
- * We handle only the first state here, in order to avoid nesting
- * switches to an ugly depth.
- * Build catalogs of the client and server folders.
- */
- if (m->f.state == 1)
- {
- if (Flags & DB_VERBOSE)
- notice (L_STARTF, m->name, nil);
- if (m->cd)
- {
- if ((m->ct = m->clientp = listFolder (ClientVol, m->cd)) == nil)
- {
- if (ClueID)
- {
- panic (false, E_SYS, nil);
- return R_BACKOUT;
- }
- }
- /*
- * Sense if we are starting on the junk folder
- */
- if (m->cd == File_list[FL_JUNK].f_info.dirID)
- m->ij = true;
- }
- if (m->sd)
- {
- if ((m->st = m->serverp = listFolder (ServerVol, m->sd)) == nil)
- {
- if (ClueID == afpAccessDenied)
- {
- notice (L_ACCESS, m->name, nil);
- }
- else if (ClueID)
- {
- panic (false, E_SYS, nil);
- return R_BACKOUT;
- }
- }
- }
- if (m->dt && m->dt->childp)
- m->distp = m->dt->childp->sibp;
- m->f.state = 2;
- return result;
- }
- break;
-
- default:
- return ( popCall (R_QUIT, nil) ); /* should not happen */
- }
-
- /*
- * Here is the bulk of the R_CONT code
- * Note that if an action requires dispatching, this code is
- * executed for each state.
- */
- clientp = m->clientp;
- serverp = m->serverp;
- distp = m->distp;
- /*
- * We are done when we reach the end of each of the three lists
- */
- if (!clientp && !serverp && !distp)
- {
- if (Flags & DB_VERBOSE)
- notice (L_ENDF, m->name, nil);
- else
- statMsgClr ();
- goto cleanexit;
- }
- /*
- * Determine the next item to work on
- */
- cname = clientp ? clientp->name : HighValue;
- sname = serverp ? serverp->name : HighValue;
- dname = distp ? distp->name : HighValue;
- wherereal = whereisit = least (cname, sname, dname);
- if ((whereisit & xxD) && distp->altname)
- {
- /*
- * If the file has an alternate name, use it after checking that
- * the alternate file exists.
- */
- serverp = &m->tsn;
- if (m->f.state == 2)
- {
- ZEROAT (serverp);
- if (getInfo (distp->altname, ServerVol, m->sd, serverp))
- serverp->dirID = 0; /* if altname doesn't exist */
- }
- if (serverp->dirID)
- whereisit |= xSx;
- else
- {
- whereisit &= ~xSx;
- serverp = nil;
- }
- }
- /*
- * Select action list from control file entry if it exists,
- * else from the defaults for this folder
- */
- if (whereisit & xxD)
- mergeActions (&m->da, &distp->actions, &ca);
- else
- ca = m->da;
- /*
- * It might fall out that the client has the right name, but it is
- * a file instead of a folder or vice versa. Handle this by working
- * with the client copy this pass and leaving the other copy for
- * the next pass (forcing junking or discarding of the client copy).
- */
- forcedIC = 0;
- if ((whereisit & CSx) == CSx && clientp->ctype != serverp->ctype)
- {
- whereisit &= ~xSD;
- wherereal &= ~xSD;
- if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
- forcedIC = A_JUNK;
- }
- if ((whereisit & CxD) == CxD && (dtype_t) clientp->ctype != distp->d_type)
- {
- whereisit &= ~xxD;
- wherereal &= ~xxD;
- if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
- forcedIC = A_JUNK;
- }
- /*
- * In a similar fashion, if a file exists on both client and server,
- * but has a different type or creator, treat the files separately.
- */
- if ((whereisit & CSx) == CSx && clientp->ctype == C_FILE)
- if (clientp->in.f.finfo.fdType != serverp->in.f.finfo.fdType
- || clientp->in.f.finfo.fdCreator != serverp->in.f.finfo.fdCreator)
- {
- whereisit &= ~xSD;
- wherereal &= ~xSD;
- if (ca.ifclient != A_DISCARD && ca.ifserver == A_UPDATE)
- forcedIC = A_JUNK;
- }
- /*
- * We know where the next file/folder is. Fetch its name and type.
- */
- if (whereisit & xxD)
- {
- ctype = (ctype_t) distp->d_type;
- name = distp->name;
- }
- else if (whereisit & xSx)
- {
- ctype = serverp->ctype;
- name = serverp->name;
- if (m->f.state <= 2 && ctype == C_FILE
- && (tp = checkTypes (m->dt, serverp)))
- mergeActions (&ca, &tp->actions, &ca);
- }
- else if (whereisit & Cxx)
- {
- ctype = clientp->ctype;
- name = clientp->name;
- if (m->f.state <= 2 && ctype == C_FILE
- && (tp = checkTypes (m->dt, clientp)))
- mergeActions (&ca, &tp->actions, &ca);
- }
- else
- {
- /*
- * Should not happen
- */
- ctype = C_FILE;
- name = (SP) "\p<cannot happen>";
- }
- if (forcedIC)
- ca.ifclient = forcedIC;
- /*
- * figure out what to do with the file/folder
- */
- if (m->f.state > 2)
- todo = m->todo;
- else
- {
- todo = ca.otherwise;
- switch (whereisit)
- {
- case xxD: /* in control file only */
- todo = ca.otherwise;
- break;
-
- case xSx: /* on server, but not client */
- case xSD:
- todo = ca.ifserver;
- if (todo == A_PASS)
- todo = ca.otherwise;
- break;
-
- case Cxx: /* on client, but not server */
- case CxD:
- todo = ca.ifclient;
- if (todo == A_PASS)
- todo = ca.otherwise;
- break;
-
- case CSx: /* on both client and server */
- case CSD:
- if (ctype == C_FOLDER)
- break;
- if (serverp->crDate != clientp->crDate && ca.ifcreate != A_PASS)
- {
- todo = ca.ifcreate;
- break;
- }
- if (serverp->mdDate > clientp->mdDate && ca.ifnewer != A_PASS)
- {
- todo = ca.ifnewer;
- break;
- }
- if (serverp->mdDate < clientp->mdDate && ca.ifolder != A_PASS)
- {
- todo = ca.ifolder;
- break;
- }
- if ((serverp->in.f.fileLen != clientp->in.f.fileLen
- || serverp->in.f.rsrcLen != clientp->in.f.rsrcLen)
- && ca.ifsize != A_PASS)
- {
- todo = ca.ifsize;
- break;
- }
- if (whereisit & xxD)
- todo = ca.otherwise;
- else
- todo = A_IGNORE;
- break;
-
- default:
- todo = A_IGNORE; /* should not happen */
- }
- }
- if (ctype == C_FOLDER)
- {
- /*
- * For a folder, E- means to use the S action instead.
- */
- if (todo == A_PASS)
- todo = ca.ifserver;
- }
- /*
- * Now that we know what to do, do it
- */
- switch (todo)
- {
- case A_IGNORE:
- if ((Flags & DB_VERBOSE) && whereisit == xxD && ca.ifserver == A_UPDATE)
- notice (L_MISSING, name, nil);
- case A_PASS:
- if (Flags & DB_VERBOSE)
- notice (L_IGNORE, name, nil);
- todo = A_IGNORE;
- break;
-
- case A_JUNK:
- if (!(whereisit & Cxx))
- break; /* if it's not on the client, who cares */
- if (m->ij)
- break; /* cannot move to junk if already in junk */
- error = moveToJunk (clientp);
- if (error != dupFNErr)
- break;
- notice (L_TOOMANYJ, name, nil);
- todo = A_DISCARD;
- /* fall into ... */
-
- case A_DISCARD:
- if (!(whereisit & Cxx))
- break; /* if not on client, can't discard */
- if (ctype == C_FILE)
- {
- error = discard (clientp, true); /* discard a file */
- break;
- }
- /*
- * Since emptying a folder can take a while, we run it under the
- * dispatcher.
- */
- if (clientp->dirID == File_list[FL_JUNK].f_info.dirID)
- break; /* leave the junk folder alone */
- switch (m->f.state)
- {
- case 2:
- paramv[0] = (Ptr) clientp;
- paramv[1] = nil;
- m->f.state = 3;
- m->todo = todo;
- result = pushCall (emptyFolder, paramv);
- if (result != R_CONT)
- m->f.state = 2;
- else
- Depth++;
- return result;
- case 3:
- /*
- * After the folder is emptied, we can discard it
- */
- Depth--;
- if (argv[0] == 0)
- error = discard (clientp, true);
- m->f.state = 2;
- }
- break;
-
- case A_UPDATE:
- if (!(whereisit & xSx))
- {
- /*
- * The junk folder often has nested folders, which do not
- * appear on the server. Do not count this as an error.
- * For any other situation, warn if the update target does
- * not exist on the server.
- */
- if (ctype == C_FILE || !(m->ij))
- {
- notice (L_MISSING, name, nil);
- todo = A_IGNORE;
- break;
- }
- }
- /*
- * If we are updating a file, use copyFile.
- * To update a folder, use ourselves.
- */
- if (ctype == C_FILE)
- {
- switch (m->f.state)
- {
- case 2:
- if (!(whereisit & Cxx))
- {
- /*
- * If file not already on client, build a dummy catalog
- * entry for it
- */
- clientp = &m->tcn;
- ZEROAT (clientp);
- clientp->ctype = ctype;
- clientp->parID = m->cd;
- COPYPS (name, clientp->name);
- }
- paramv[0] = (Ptr) serverp;
- paramv[1] = (Ptr) clientp;
- paramv[2] = (Ptr) m->name;
- m->f.state = 3;
- m->todo = todo;
- result = pushCall (copyFile, paramv);
- if (result != R_CONT)
- m->f.state = 2;
- return result;
-
- case 3:
- m->f.state = 2;
- if (!(whereisit & Cxx))
- {
- clientp = &m->tcn;
- whereisit |= Cxx;
- }
- }
- break;
- }
- /*
- * Here for folder update
- */
- switch (m->f.state)
- {
- case 2:
- /*
- * If the folder is not in the control list, use the dummy
- * dnode to describe it while it is being updated.
- */
- if (! (whereisit & xxD) )
- {
- distp = &m->tdn;
- ZEROAT (distp);
- COPYPS (name, distp->name);
- if (m->dt) /* propagate type list */
- distp->tlistp = m->dt->tlistp;
- }
- else
- if (distp && distp->childp)
- mergeActions (&m->da, &distp->childp->actions, &ca);
- /*
- * If the folder does not exist yet on client, create it.
- */
- if (! (whereisit & Cxx))
- {
- clientp = &m->tcn;
- if (Flags & DB_LISTONLY)
- {
- notice (L_WCREATE, name, nil);
- ZEROAT (clientp);
- clientp->ctype = ctype;
- }
- else
- {
- error = createFolder (name, ClientVol, m->cd, serverp);
- if (error == 0)
- error = getInfo (name, ClientVol, m->cd, clientp);
- if (error)
- {
- warning (E_SYS, nil);
- error = 0;
- break;
- }
- }
- whereisit |= Cxx;
- }
- if (clientp->attrib & fLocked)
- (void) unlock (clientp);
- paramv[0] = (Ptr) distp;
- paramv[1] = (Ptr) &ca;
- if (whereisit & xSx)
- paramv[2] = (Ptr) &serverp->dirID;
- else
- {
- temp = 0;
- paramv[2] = (Ptr) &temp;
- }
- paramv[3] = (Ptr) &clientp->dirID;
- paramv[4] = (Ptr) &m->ij;
- m->f.state = 3;
- m->todo = todo;
- result = pushCall (matchFolder, paramv);
- if (result != R_CONT)
- m->f.state = 2;
- else
- Depth++;
- return result;
- case 3:
- m->f.state = 2;
- Depth--;
- if (!(whereisit & Cxx))
- {
- clientp = &m->tcn;
- whereisit |= Cxx;
- }
- if (serverp && (serverp->attrib & fLocked) &&
- !(Flags&DB_LISTONLY))
- (void) relock (clientp);
- break;
- }
- break;
-
- default:
- notice (L_NOWHAT, name, nil);
- break;
- } /* end of todo switch */
- if (error == fBsyErr)
- error = 0; /* ignore busy file: it may be us
- * or we may be running under
- * MultiFinder */
- /*
- * Update Finder information, if requested.
- */
- if ((todo == A_UPDATE || todo == A_IGNORE) && error == 0)
- if (ca.copywindow == A_UPDATE || ca.invisible >= A_JUNK
- || ca.locked >= A_JUNK)
- updateFInfo (clientp, serverp, whereisit,
- ca.copywindow, ca.invisible, ca.locked);
- if (wherereal & xxD)
- m->distp = m->distp->sibp;
- if (wherereal & xSx)
- m->serverp = m->serverp->link;
- if (wherereal & Cxx)
- m->clientp = m->clientp->link;
- if ((error || Quit) && result < R_BACKOUT)
- result = R_BACKOUT;
- return result;
-
- cleanexit:
- if (GetHandleSize ((Handle)fh) >= sizeof (lm_t))
- {
- freeList (m->ct);
- freeList (m->st);
- }
- return (popCall (result, nil));
- }
-
-
-
- /*
- *=========================================================================
- * checkTypes (dp, cp) - find type_node applying to file
- * entry: dp = ptr to dnode of folder containing file
- * cp = ptr to catalog node describing file
- * exit: returns ptr to type_list which applies (possibly nil)
- *=========================================================================
- */
-
- tnode_t *
- checkTypes (dp, cp)
- dnode_t * dp;
- cnode_t * cp;
- {
- register OsType ft; /* file type */
- register OsType fc; /* file creator */
- register tnode_t * tp; /* type_node ptr */
-
- tp = dp->tlistp;
- if (cp == nil || tp == nil)
- return nil;
- ft = cp->in.f.finfo.fdType;
- fc = cp->in.f.finfo.fdCreator;
- if (ft == 0)
- ft = '????';
- if (fc == 0)
- fc = '????';
- for (; tp; tp = tp->morep)
- {
- if (tp->ftype && tp->ftype != ft)
- continue; /* mismatch on type */
- if (tp->fcreator && tp->fcreator != fc)
- continue; /* mismatch on creator */
- break;
- }
- return tp;
- }
-
-
-
-
- /*
- *=========================================================================
- * least (c, s, d) - find alphabetical least of three strings
- * entry: c = client name string
- * s = server name string
- * d = control file name string
- * returns: bit pattern indicating which of the sources has the least string
- *=========================================================================
- */
- short
- least (c, s, d)
- register StringPtr c, s, d;
- {
- switch (RelString (c, s, false, true))
- {
- case -1: /* C < S, find lesser of C and D */
- switch (RelString (c, d, false, true))
- {
- case -1: return Cxx;
- case 0: return CxD;
- case 1: return xxD;
- }
- case 0: /* C == S, how about D */
- switch (RelString (c, d, false, true))
- {
- case -1: return CSx;
- case 0: return CSD;
- case 1: return xxD;
- }
- case 1: /* S < C, find lesser of S and D */
- switch (RelString (s, d, false, true))
- {
- case -1: return xSx;
- case 0: return xSD;
- case 1: return xxD;
- }
- }
- /*NOTREACHED*/
- return 0;
- }
-
-
-
- /*
- *=========================================================================
- * mergeActions (def, src, dst) - merge default and specific action lists
- * entry: def = pointer to default action list
- * src = pointer to specific action list
- * dst = pointer to list for result of merge
- * def and dst can be the same without confusion
- *=========================================================================
- */
- void
- mergeActions (def, src, dst)
- register actions_t * def;
- register actions_t * src;
- register actions_t * dst;
- {
- register action_t a;
-
- /*
- * Easy. Just copy the src to the dst, supplying values from def
- * whereever src action is A_DEFAULT
- */
- dst->ifclient = (a = src->ifclient ) != A_DEFAULT ? a: def->ifclient;
- dst->ifserver = (a = src->ifserver ) != A_DEFAULT ? a: def->ifserver;
- dst->ifcreate = (a = src->ifcreate ) != A_DEFAULT ? a: def->ifcreate;
- dst->ifnewer = (a = src->ifnewer ) != A_DEFAULT ? a: def->ifnewer;
- dst->ifolder = (a = src->ifolder ) != A_DEFAULT ? a: def->ifolder;
- dst->ifsize = (a = src->ifsize ) != A_DEFAULT ? a: def->ifsize;
- dst->otherwise = (a = src->otherwise ) != A_DEFAULT ? a: def->otherwise;
- dst->copywindow = (a = src->copywindow) != A_DEFAULT ? a: def->copywindow;
- dst->invisible = (a = src->invisible ) != A_DEFAULT ? a: def->invisible;
- dst->locked = (a = src->locked ) != A_DEFAULT ? a: def->locked;
- }
-
-
- /*
- *=========================================================================
- * updateFInfo (cp, sp, where, window, hide) - change Finder info for client
- * file/folder
- * entry: cp = pointer to client catalog node
- * sp = pointer to server catalog node
- * where = bits for which of cp and sp are valid
- * window = A_UPDATE to copy server info to client
- * hide = A_JUNK to make invisible, A_DISCARD to make visible,
- * or A_UPDATE to copy server to client
- * lock = same as hide, but for locked attribute
- * Since this is just a frill, errors are silently ignored
- *=========================================================================
- */
- static
- void
- updateFInfo (cp, sp, where, window, hide, lock)
- register cnode_t * cp;
- register cnode_t * sp;
- short where;
- action_t window;
- action_t hide;
- action_t lock;
- {
- int doit; /* non-zero if need to change client */
- OSErr error;
- register long * cl, *sl; /* used to speed compares */
- int have; /* current client visibility or lock */
- Integer temp; /* temp to hold client file folder info */
- int wantl; /* lockedness wanted on client */
- int wantv; /* visibility wanted on client */
- CInfoPBRec ci;
-
- if ((where & Cxx) == 0 || cp == 0)
- return; /* if not on client, can't do anything */
- doit = 0;
- /*
- * Check if need to change visibility
- */
- have = cp->in.f.finfo.fdFlags & fInvisible;
- switch (hide)
- {
- case A_JUNK: wantv = fInvisible; break;
- case A_DISCARD: wantv = 0; break;
- case A_UPDATE: if (sp)
- { wantv = sp->in.f.finfo.fdFlags & fInvisible; break; }
- default: wantv = have;
- }
- if (have != wantv)
- doit |= 2;
- /*
- * If we should update the window info from the server and the
- * server exists and the info differs between the client and server,
- * then we need to do the update.
- */
- if ((where & xSx) && sp && window == A_UPDATE)
- {
- cp->in.f.finfo.fdFlags &= ~fInvisible;
- temp = sp->in.f.finfo.fdFlags;
- sp->in.f.finfo.fdFlags &= ~fInvisible;
- switch (cp->ctype)
- {
- case C_FILE:
- if (cp->in.f.finfo.fdType != sp->in.f.finfo.fdType
- || cp->in.f.finfo.fdCreator != sp->in.f.finfo.fdCreator
- || cp->in.f.finfo.fdFlags != sp->in.f.finfo.fdFlags
- || *(long *)&cp->in.f.finfo.fdLocation !=
- *(long *)&sp->in.f.finfo.fdLocation
- )
- doit = 1;
- break;
- case C_FOLDER:
- cl = (long *)&cp->in.d.dinfo;
- sl = (long *)&sp->in.d.dinfo;
- if (cl[0] != sl[0] /* frRect top, left */
- || cl[1] != sl[1] /* frRect bottom, right */
- || cl[2] != sl[2] /* frFlags & frLocation.v */
- || cl[3] != sl[3] /* frLocation.h & frView */
- || cp->in.d.frScroll.v != sp->in.d.frScroll.v
- || cp->in.d.frScroll.h != sp->in.d.frScroll.h
- || (cp->in.d.frOChain != 0 && sp->in.d.frOChain == 0)
- )
- doit = 1;
- break;
- }
- }
- /*
- * Now check lock/unlock
- */
- have = cp->attrib & fLocked;
- switch (lock)
- {
- case A_JUNK: wantl = fLocked; break;
- case A_DISCARD: wantl = 0; break;
- case A_UPDATE: if (sp)
- { wantl = sp->attrib & fLocked; break; }
- default: wantl = have;
- }
- if (have != wantl)
- doit |= 4;
- /*
- * If we need to change client's info, get the current values again,
- * change them, and set them back.
- */
- if (doit)
- {
- ZERO (ci);
- ci.hFileInfo.ioVRefNum = ClientVol;
- if (cp->ctype == C_FILE)
- {
- ci.hFileInfo.ioNamePtr = cp->name;
- ci.hFileInfo.ioDirID = cp->parID;
- ci.hFileInfo.ioFDirIndex = 0;
- }
- else
- {
- ci.hFileInfo.ioDirID = cp->dirID;
- ci.hFileInfo.ioFDirIndex = -1;
- }
- error = PBGetCatInfo (&ci, false);
- if (error)
- return;
- if (doit & 1)
- {
- if (cp->ctype == C_FILE)
- {
- temp = ci.hFileInfo.ioFlFndrInfo.fdFldr;
- ci.hFileInfo.ioFlFndrInfo = sp->in.f.finfo;
- ci.hFileInfo.ioFlFndrInfo.fdFldr = temp;
- }
- else
- {
- ci.dirInfo.ioDrUsrWds = sp->in.d.dinfo;
- ci.dirInfo.ioDrFndrInfo.frScroll = sp->in.d.frScroll;
- if (sp->in.d.frOChain == 0)
- ci.dirInfo.ioDrFndrInfo.frOpenChain = 0;
- }
- }
- ci.hFileInfo.ioFlFndrInfo.fdFlags =
- (ci.hFileInfo.ioFlFndrInfo.fdFlags & ~fInvisible) | wantv;
- ci.hFileInfo.ioFlAttrib =
- (ci.hFileInfo.ioFlAttrib & ~fLocked) | wantl;
- if (Flags & DB_VERBOSE)
- notice (L_FINFO, cp->name);
- if (Flags & DB_LISTONLY)
- return;
- if (cp->ctype == C_FILE)
- {
- ci.hFileInfo.ioDirID = cp->parID;
- ci.hFileInfo.ioFDirIndex = 0;
- }
- error = PBSetCatInfo (&ci, false);
- if (error)
- {
- ClueID = error;
- notice (L_SYS, (SP)"\pUpdateFInfo", (SP)"\pPBSetCatInfo",nil);
- }
- /*
- * Since changing the fLocked bit in the attributes doesn't really
- * lock or unlock anything (Why?), we may need to explicitly lock
- * or relock the file/folder.
- */
- if (doit & 4)
- {
- if (wantl)
- relock (cp);
- else
- unlock (cp);
- }
- }
- }
-
-
- /*
- *=========================================================================
- * updateRoot (dp) - update finder window information for client root folder
- * entry: dp = pointer to dist_node for client root folder
- * technique: just set up can call updateFInfo ()
- *=========================================================================
- */
- void
- updateRoot (dp)
- dnode_t *dp;
- {
- cnode_t *clientp, *serverp; /* args for updateFInfo () */
- actions_t *ra; /* action list for root */
- file_info_t *fi; /* ptr into File_list[] */
-
- /*
- * Exit if nothing to do.
- * Note that most of these exit conditions should never happen!
- */
- if (! dp)
- return;
- fi = &File_list[FL_ROOT];
- if (! fi->f_set)
- return;
- clientp = &fi->f_info;
- fi = &File_list[FL_MAST];
- if (! fi->f_set)
- return;
- serverp = &fi->f_info;
- ra = &dp->actions;
- if (ra->copywindow == A_UPDATE
- || ra->invisible >= A_JUNK
- || ra->locked >= A_JUNK)
- {
- updateFInfo (clientp, serverp, CSD,
- ra->copywindow, ra->invisible, ra->locked);
- }
- }